﻿#include"head.h"

pthread_t tid;  //创建线程id	
	
typedef struct info{
	int fd;
	struct in_addr sin_addr;                        
	u_short sin_port;
	char buf[SIZE];
}Clientinfo,*Cp;

void System_clear()
{
	system("clear");
}

void* server_routine(void* arg)
{
	int fd = *(int*)arg;
	int readsize;
	char buf[SIZE];
	while(1)
	{
		bzero(buf,SIZE);
		readsize = read(fd,buf,SIZE);	
		if(readsize<0)
		{
			perror("client read failed");
		}else if(readsize>0){
			printf("\t\t\tfrom server message:%s\n",buf);	
		}
	}
	pthread_exit(NULL);
}
          
                                               
//UI界面                        		
int ui_windows()
{	
	puts("\t\t\t========================\n");
	printf("\t\t\t1.更新好友列表\n");
	printf("\t\t\t2.选择好友，聊天\n");
	printf("\t\t\t3.退出\n");
	//while(getchar()!='\n');
	
	int num = 0;
	printf("请选择选项:");
	scanf("%d",&num);
return num;
}
                                                        
void updata_list(int fd)
{
	//每次获取朋友圈列表之前，都需要清屏
	System_clear();
	
	Clientinfo info;
	Dlist nodeinfo;
	int num;
	
	//向服务器发送"list"
	write(fd,"list",4);
	
	//接收好友数量
	read(fd,&num,4);

	printf("num:%d\n",num);
	
	for(int i=0;i<num;i++)
	{
		//读取好友信息IP、PORT、昵称
		read(fd,&nodeinfo,sizeof(struct list_head));
		printf("[昵称：] IP:%s  PORT:%hu\n",inet_ntoa(nodeinfo.sin_addr),ntohs(nodeinfo.sin_port));
	}
}

void interact_message(int fd)
{
	//创建线程，用于从服务器接收数据
	pthread_create(&tid,NULL,server_routine,(void*)&fd);
	
	//向服务器发送chat命令
	write(fd,"chat",4);
	
	//发送数据
	Clientinfo ctos ;
	int writesize,readsize,button;
	char bufip[20];
	char bufport[4];
	char buftext[SIZE]={0};
	printf("请输入好友IP PORT: ");
	scanf("%s %s", bufip,bufport);
	ctos.sin_addr.s_addr = inet_addr(bufip);
	ctos.sin_port = htons(atoi(bufport));  
	
	//为了界面美观
	System_clear();
	
	//先将好友信息发给服务器
	writesize = write(fd,&ctos,sizeof(struct info)); 
		
	while(1)
	{	
		
		
		puts("\t\t\t========================\n");
		printf("\033[0;34m \t\t\t1.请输入您要发的消息\n\t\t\t2.发送文件\n\t\t\t3.quit返回上一层\n \033[0m");
		printf("请选择选项：");
		scanf("%d",&button);
		if(button == 1)
		{
			write(fd,"chat0001",8);
			while(1)
			{
				printf("cd return\[input:]");
				bzero(buftext,sizeof(buftext));
				gets(buftext);

				//向服务器发送消息
				writesize = write(fd,buftext,sizeof(buftext));    //write函数文件描述符是SOCKET，则此函数默认是阻塞的
													 // //UI界面
				printf("write %s %lu byte ip:%s port%hu\n",buftext,strlen(buftext),\
				inet_ntoa(ctos.sin_addr),ctos.sin_port);		             
				
				if(!strcmp(buftext,"cd")) break;  
			}
			
		}else if(button == 2)
		{
			write(fd,"sentfile",8);
			char bufd[SIZE]={0};
			bzero(bufd,SIZE);
			printf("请输入你要发送文件的路径：");
			fgets(bufd,SIZE,stdin);
			int sendfd = open(bufd,O_RDONLY,0666);
			//读取文件，返回0时，退出循环
			while(readsize = read(sendfd,buftext,SIZE))
			{
				if(readsize > 0){
					write(fd,buftext,readsize);
				}else if(readsize <0)
				{
					perror("send file error!");
				}
			}	
		}else if(button == 3)
		{
			//向服务器发送quit命令
			write(fd,"quit",4);
			
			//等待线程先将quit读取
			sleep(1);
			pthread_cancel(tid);
			break;                                                       
		
		}

	}                                                                         
	                                                                             
}

void exit_load(int fd)
{
	write(fd,"quit",4);  //向服务器发送quit命令，表示本客户端已退出
	pthread_cancel(tid);
	close(fd);
}

int main(int argc,char* argv[])
{
	if(argc != 3)
	{
		fprintf(stderr,"usage: %s <IP> <PORT>\n",argv[0]);
		exit(1);
	}

	//创建套接字
	int socket_tcp = socket(AF_INET,SOCK_STREAM,0);
	if(socket_tcp == -1)
	{
		perror("socket failed");
		
	}

	//定义包含IP/PORT的结构体,指定server的IP/PORT
	struct sockaddr_in serveraddr_info;
	serveraddr_info.sin_family = AF_INET;
	serveraddr_info.sin_port = htons(atoi(argv[2]));  //必须转换成网络字节序
	serveraddr_info.sin_addr.s_addr =  inet_addr(argv[1]);  //将字符串转化为32bit网络字节序
	socklen_t serveraddr_len = sizeof(serveraddr_info);

	//从本端连接服务器，对端监听套接字
	int retconnt = connect(socket_tcp ,(struct sockaddr*)&serveraddr_info,serveraddr_len);
	if(retconnt == -1 )
	{
		perror(" client connect failed");
		exit(1);
	}

	//第一次打开程序时，界面清屏
	System_clear();
	
	int flag=0;
	while(1)
	{	
		if(flag ==0)
		{
			//QQ界面
			int number = ui_windows();	
			
			//相应功能
			switch(number)
			{
				case 1:updata_list(socket_tcp);break; //将自己的好友列表呈现出来
				case 2:interact_message(socket_tcp);break;//选择好友，通信
				case 3:exit_load(socket_tcp); flag = 1;   //退出
			}
	
		}else if(flag ==1)
		{
			break;
		}
		
	}
                                                                                                                                                            
return 0;
}


































